package com.cino.demos.sourceCode.mybatisDemo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Mapper代理类 - 动态代理的核心实现
 * 
 * 实现InvocationHandler接口，负责拦截所有Mapper接口的方法调用
 */
public class MapperProxy implements InvocationHandler {
    
    // 关联的SQL会话
    private final SqlSession sqlSession;
    
    public MapperProxy(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    /**
     * 代理方法拦截器 - 所有Mapper接口方法调用都会进入这里
     * 
     * 动态代理的核心方法，当调用代理对象的任何方法时，都会触发此方法
     * 
     * @param proxy 代理对象本身（通常不使用）
     * @param method 被调用的方法对象
     * @param args 方法参数
     * @return 方法执行结果
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1. 处理Object类的方法（toString, hashCode, equals等）
        if (method.getDeclaringClass() == Object.class) {
            return handleObjectMethod(proxy, method, args);
        }
        
        // 2. 构建方法唯一标识（接口名.方法名）
        String methodId = buildMethodIdentifier(method);
        
        // 3. 交给SqlSession执行数据库操作
        return sqlSession.execute(methodId, args);
    }
    
    /**
     * 处理Object类的基础方法
     * 
     * 确保代理对象的基本行为正常（如toString输出有意义的信息）
     */
    private Object handleObjectMethod(Object proxy, Method method, Object[] args) {
        String methodName = method.getName();
        
        // 根据方法名进行不同的处理
        switch (methodName) {
            case "toString":
                // 返回代理对象的描述信息
                return "MapperProxy@" + Integer.toHexString(hashCode()) + " for " + sqlSession;
                
            case "hashCode":
                // 返回代理对象的哈希码
                return System.identityHashCode(proxy);
                
            case "equals":
                // 比较代理对象是否相同
                return proxy == args[0];
                
            default:
                // 其他Object方法（理论上不会执行到这里）
                try {
                    return method.invoke(this, args);
                } catch (Exception e) {
                    throw new RuntimeException("处理Object方法失败: " + methodName, e);
                }
        }
    }
    
    /**
     * 构建方法唯一标识符
     * 
     * 实际MyBatis中会使用全限定名（包名+类名+方法名）
     * 这里简化为接口名+方法名，保持示例简洁
     */
    private String buildMethodIdentifier(Method method) {
        return method.getDeclaringClass().getSimpleName() + "." + method.getName();
    }
}